package com.vecspace.data.numerical;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Types;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.UserType;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.vecspace.utils.NumberUtil;

public abstract class HNumerical implements UserType, Serializable{
	private static final long serialVersionUID = 1707677424903719801L;

	private BigDecimal value;

	private EnumNumericalSeparatorDigit separatorDigit = EnumNumericalSeparatorDigit.WanWeiSplit;
	
	/**WanWeiSplit,QianWeiSplit*/
	//protected static ThreadLocal<EnumNumericalSeparatorDigit> tlSeparatorDigit = new ThreadLocal<EnumNumericalSeparatorDigit>();

	/**将格式化为字符串时，使用千分位分隔符还是万分位分隔符<br>
	 * 千分位 123,456,789.123<br>
	 * 万分位 1234,5678.123
	 * @return 
	 * @author: wanghua
	 */
	protected EnumNumericalSeparatorDigit getSeparatorDigit() {
//		EnumNumericalSeparatorDigit separatorDigit2 = tlSeparatorDigit.get();
//		if(separatorDigit2 != null && separatorDigit2 != EnumNumericalSeparatorDigit.Unkown) {//优先使用线程内定义的分隔位。
//			return separatorDigit2;
//		}		
//		if(this.separatorDigit == null || this.separatorDigit == EnumNumericalSeparatorDigit.Unkown) {
//			return separatorDigit2;
//		}
//		else return separatorDigit;
		return separatorDigit;
	}
	
	public void setSeparatorDigit(EnumNumericalSeparatorDigit separatorDigit) {
		this.separatorDigit = separatorDigit;
	}
	
	/**设置小数位数
	 * RoundingMode.HALF_UP
	 * @param newScale 
	 * @author: wanghua
	 */
	public void setScale(int newScale) {
		if(this.value != null) {
			this.value = this.value.setScale(newScale, RoundingMode.HALF_UP);
		}
	}
	
	public BigDecimal parseDouble(String text) {
		if(text == null || text.length() == 0) return BigDecimal.ZERO;
		String str = text.trim();
		str = str.replace(" ", "");
		str = str.replace("　", "");
		str = str.replace(",", "");
		str = str.replace("，", "");
		str = str.replace("￥", "");
		str = str.replace("¥", "");
		str = str.replace("%", "");
		str = str.replace("％", "");
		if(text.length() == 0) return BigDecimal.ZERO;
		BigDecimal num = new BigDecimal(str);
		return num;
	}
	/**
	 * 
	 * @param separatorDigit 
	 * @author: wanghua
	 */
//	public static void setThreadLocalSeparatorDigit(EnumNumericalSeparatorDigit separatorDigit) {
//		tlSeparatorDigit.set(separatorDigit);
//	}

	public BigDecimal getValue() {
		return value;
	}

	public void setValue(BigDecimal value) {
		this.value = value;
	}

	@Override
	public int[] sqlTypes() {
		return new int[]{Types.NUMERIC};
	}
	

	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if(x == null || y == null)return false;
		if(x == y)return true;		
		HNumerical num1 = (HNumerical)x;
		HNumerical num2 = (HNumerical)y;
		if(num1.value == null || num2.value == null)return false;
		return NumberUtil.equals(num1.value, num2.value, 0.0000001);
	}
	
	public static boolean equals(HNumerical num1, HNumerical num2) throws HibernateException {
		if(num1 == null || num2 == null)return false;
		if(num1 == num2)return true;
		if(num1.value == null || num2.value == null)return false;
		return NumberUtil.equals(num1.value, num2.value, 0.0000001);
	}

	@Override
	public int hashCode(Object x) throws HibernateException {
		if(value == null)return 0;
		return value.hashCode();
	}

	@JsonIgnore
	@Override
	public boolean isMutable() {
		return false;
	}


	@Override
	public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
			throws HibernateException, SQLException {
		if(value != null) {
			HNumerical obj = (HNumerical)(value);
			BigDecimal val = obj.getValue();
			st.setBigDecimal(index, val);
		}else {
			st.setNull(index, Types.NUMERIC);   //保存空值
		}
	}

	@Override
	public Serializable disassemble(Object value) throws HibernateException {
		 return (HNumerical)deepCopy(value);
	}

	@Override
	public Object assemble(Serializable cached, Object owner) throws HibernateException {
		return deepCopy(cached);
	}

	@Override
	public Object replace(Object original, Object target, Object owner) throws HibernateException {
		return deepCopy(original);
	}

	public abstract String getText();

	/**
	 * 
	 * @param text 
	 * @author: wanghua
	 */
	public abstract void setText(String text);
	
	
	/**两个数相加，null相当于0
	 * 
	 * @param num1
	 * @param num2 
	 * @author: wanghua
	 */
	public static BigDecimal add(HNumerical num1, HNumerical num2) {
		BigDecimal d1 = BigDecimal.ZERO;
		BigDecimal d2 = BigDecimal.ZERO;
		if(num1 != null && num1.value != null) {
			d1 = num1.value;
		}
		if(num2 != null && num2.value != null) {
			d2 = num2.value;
		}
		return d1.add(d2);
	}
	
	/**两个数相减，null相当于0
	 * 
	 * @param num1
	 * @param num2 
	 * @author: wanghua
	 */
	public static BigDecimal subtract(HNumerical num1, HNumerical num2) {
		BigDecimal d1 = BigDecimal.ZERO;
		BigDecimal d2 = BigDecimal.ZERO;
		if(num1 != null && num1.value != null) {
			d1 = num1.value;
		}
		if(num2 != null && num2.value != null) {
			d2 = num2.value;
		}
		return d1.subtract(d2);
	}
	
	/**两个数相乘，遇到null返回null
	 * 
	 * @param num1
	 * @param num2 
	 * @author: wanghua
	 */
	public static BigDecimal multiply(HNumerical num1, HNumerical num2) {
		if(num1 == null || num1.getValue() == null)return null;
		if(num2 == null || num2.getValue() == null)return null;
		BigDecimal d1 = num1.getValue();
		BigDecimal d2 = num2.getValue();
		BigDecimal d3 = d1.multiply(d2);
		int scale = d1.scale() > d2.scale() ? d1.scale() : d2.scale();
		d3 = d3.setScale(scale, RoundingMode.HALF_UP);
		return d3;
	}
	
	/**两个数相乘，遇到null返回null
	 * 
	 * @param num1
	 * @param num2 
	 * @author: wanghua
	 */
	public static BigDecimal multiply(HNumerical num1, BigDecimal num2) {
		if(num1 == null || num1.getValue() == null)return null;
		if(num2 == null)return null;
		BigDecimal d1 = num1.getValue();
		BigDecimal d2 = num2;
		BigDecimal d3 = d1.multiply(d2);
		int scale = d1.scale() > d2.scale() ? d1.scale() : d2.scale();
		d3 = d3.setScale(scale, RoundingMode.HALF_UP);
		return d3;
	}
	
	/**两个数相乘，遇到null返回null
	 * 
	 * @param num1
	 * @param num2 
	 * @author: wanghua
	 */
	public static BigDecimal multiply(BigDecimal num1, BigDecimal num2) {
		if(num1 == null)return null;
		if(num2 == null)return null;
		BigDecimal d1 = num1;
		BigDecimal d2 = num2;
		BigDecimal d3 = d1.multiply(d2);
		int scale = d1.scale() > d2.scale() ? d1.scale() : d2.scale();
		d3 = d3.setScale(scale, RoundingMode.HALF_UP);
		return d3;
	}
	
	/**两个数相除，遇到null返回null
	 * 
	 * @param num1
	 * @param num2 
	 * @author: wanghua
	 */
	public static BigDecimal divide(HNumerical num1, HNumerical num2) {
		if(num1 == null || num1.getValue() == null)return null;
		if(num2 == null || num2.getValue() == null)return null;
		
		BigDecimal d1 = num1.getValue();
		BigDecimal d2 = num2.getValue();
		
		if(d2.equals(BigDecimal.ZERO))return null;// 0 not equals 0.00
		if(d2.abs().doubleValue() < 0.0000000001)return null;
		
		int scale = d1.scale() > d2.scale() ? d1.scale() : d2.scale();
		return d1.divide(d2, scale, RoundingMode.HALF_UP);
	}
	
	/**返回numerical代表的BigDecimal，如果numerical为null，则返回null
	 * 
	 * @param numerical
	 * @return 
	 * @author: wanghua
	 */
	public static BigDecimal getBigDecimalValue(HNumerical numerical) {
		if(numerical == null)return null;
		return numerical.getValue();
	}
	
	public double doubleValue() {
		BigDecimal decimal = this.getValue();
		if(decimal == null)return 0.0;
		else return decimal.doubleValue();
	}
}
